<?php
class stock {
  function __construct() {
  }

  public function select() {
  
    $data = new jqGridData();
    try
    {
// Только зарегистрированные пользователи могут видеть данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

		$rwd = $_SESSION['priv']->stock->rwd;
		if( !$rwd  ) throw new Exception(ERR_M::DATA_ACC_DISABLED, 99);

// Проверяем данные
        $page    = ( isset($_REQUEST["page"]) && $_REQUEST["page"] > 0 ) ? $_REQUEST["page"] : 1;
        $limit    = ( isset($_REQUEST["rows"]) && $_REQUEST["rows"] > 0 ) ? $_REQUEST["rows"] : 1;
        $sidx    = ( isset($_REQUEST["sidx"]) && $_REQUEST["sidx"] != '' ) ? $_REQUEST["sidx"] : 'sto_id';
        $sord    = ( isset($_REQUEST["sord"]) && strtolower($_REQUEST["sord"]) == 'desc' ) ? 'DESC' : 'ASC';
        $search    = ( isset($_REQUEST["_search"]) && strtolower($_REQUEST["_search"]) == 'true') ? true : false;
 
        $leaf_id = isset($_REQUEST["leaf_id"]) ? $_REQUEST["leaf_id"] : '';             
        if ( !ctype_digit($leaf_id) )
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Сортировка
		switch( $sidx ) {
			case 'sto_id': $sidx = 'sto.sto_id'; break;
			case 'sto_inv_date': $sidx = 'sto.sto_key'; break;
			case 'sto_inv_num': $sidx = 'sto.sto_inv_num, sto.sto_inv_pos'; break;
			case 'sto_remain': $sidx = 'sto.sto_remain'; break;
			case 'uni_name': $sidx = 'uni.uni_name'; break;
//			case 'uni_full': $sidx = 'uni.uni_full'; break;
		}
		
// Фильтр
        $whc = array();
        if( $search )
        {
            if(isset($_REQUEST["sto_id"]) && is_numeric($_REQUEST["sto_id"]) ) {
				$whc[] = "sto_id=" . $db->quote($_REQUEST["sto_id"]);
		    }
            
            if(isset($_REQUEST["sto_inv_date"]) && ( $dt = Tools::date_to_search_str( $_REQUEST["sto_inv_date"] )) != "") {
				$whc[] = "sto_inv_date LIKE " . $db->quote("%".$dt."%");
            }
			
            if(isset($_REQUEST["sto_inv_num"]) && $_REQUEST["sto_inv_num"] != "") {
				$whc[] = "sto_inv_num LIKE " . $db->quote("%".$_REQUEST["sto_inv_num"]."%");
            }
			
            if(isset($_REQUEST["uni_name"]) && $_REQUEST["uni_name"] != "") {
		    	$whc[] = "uni.uni_name LIKE " . $db->quote("%".$_REQUEST["uni_name"]."%");
            }
			
            if(isset($_REQUEST["uni_full"]) && $_REQUEST["uni_full"] != "") {
		    	$whc[] = "uni.uni_full LIKE " . $db->quote("%".$_REQUEST["uni_full"]."%");
            }
			
		}

// Фильтр привилегий
		if( $rwd & PERM_BITS::READ_OTH ) $whc[] = '1 = 1';
		elseif( $rwd & PERM_BITS::READ_GRP ) 
			$whc[] = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::READ_OWN ) $whc[] = 'sto_user_id = '.$_SESSION['user_id'];
		else $whc[] = '1 = 0';

// Отсекаем списанные записи
		$whc[] = 'sto_retire_date IS NULL';
		
// Окончательно формируем условие
        $whereclaus = (count($whc) != 0 ) ? " WHERE " . implode(" AND ", $whc) : "";
		unset($whc);
            
// Получаем количество записей с учетом фильтра
		$uni_filter = $leaf_id ? "AND uni_leaf_id = ".$db->quote( $leaf_id )." " : '';
			
        $join1 = " INNER JOIN units AS uni ON uni.uni_id = sto.sto_uni_id ".$uni_filter;
        $join2 = " INNER JOIN metrics AS met ON met.met_id = sto.sto_metric ";
            
        $sqlreq = "SELECT COUNT(*) AS count FROM stock AS sto ".$join1.$whereclaus;
        $recset = $db->query( $sqlreq );
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		$count = $row['count'];
		$recset->closeCursor();
            
// Пустая таблица
        if ($count == 0)
			throw new Exception(ERR_M::SUCCESS, 0);
            
// Рассчитаем сколько всего страниц займут данные в БД
    	if( $count > 0 && $limit > 0) {
    		$total_pages = ceil($count/$limit);
    	} else {
    		$total_pages = 0;
    	}                  
 
		if ($page > $total_pages) $page=$total_pages;                  
 
		$start = $limit*$page - $limit;                   
		if($start < 0) $start = 0;                  
 
// Формируем запрос
		$sqlreq = 	'SELECT  sto_id, sto_inv_date, sto_inv_num, sto_inv_pos, sto_uni_id, uni_name, uni_full, '.
							'sto_number, sto_remain, sto_metric, met_name, sto_price, sto_comment, sto_create_date '.
					'FROM stock AS sto '.$join1.$join2.$whereclaus." ORDER BY ".$sidx." ".$sord.
		            " LIMIT ".$start.", ".$limit;

		$recset = $db->query($sqlreq);                  
 
// Формирование объекта для возврата
        
    	$data->page      = $page;
    	$data->total     = $total_pages;
    	$data->records   = $count;
    		
    // Строки данных для таблицы
		$currdate = date('Y-m-d');
		$i = 0;
		while($row = $recset->fetch(PDO::FETCH_ASSOC)) {
			$status = 0;
			if( $currdate != $row['sto_create_date'] ) $status |= 2;
			if( $row['sto_number'] != $row['sto_remain'] ) $status |= 4;
			
			$data->rows[$i]['id'] = $row['sto_id'];
			$data->rows[$i]['cell'] = array(
					$status,
					$row['sto_id'],
					Tools::str_iso2local_date( $row['sto_inv_date'] ),
					$row['sto_inv_num'],
					$row['sto_inv_pos'],
					$row['sto_uni_id'],
					$row['uni_name'],
					$row['uni_full'],
					$row['sto_number'],
					$row['sto_remain'],
				    $row['sto_metric'],
				    $row['met_name'],
				    $row['sto_price'],
				    $row['sto_comment']
		    );
		    $i++;
		}
    }
	catch (PDOException $e) {
		$data->userdata->errcode = 1;
		$data->userdata->errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$data->userdata->errcode = $e->getCode();
		$data->userdata->errmess = $e->getMessage();
	}
 
	return $data;
  }
  

  public function find() {
  
    $data = new jqGridData();
    try
    {
// Только зарегистрированные пользователи могут видеть данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

		$rwd = $_SESSION['priv']->stock->rwd;
		if( !$rwd  ) throw new Exception(ERR_M::DATA_ACC_DISABLED, 99);

// Проверяем данные
        $page    = ( isset($_REQUEST["page"]) && $_REQUEST["page"] > 0 ) ? $_REQUEST["page"] : 1;
        $limit    = ( isset($_REQUEST["rows"]) && $_REQUEST["rows"] > 0 ) ? $_REQUEST["rows"] : 1;
        $sidx    = ( isset($_REQUEST["sidx"]) && $_REQUEST["sidx"] != '' ) ? $_REQUEST["sidx"] : 'sto_id';
        $sord    = ( isset($_REQUEST["sord"]) && strtolower($_REQUEST["sord"]) == 'desc' ) ? 'DESC' : 'ASC';
        $search    = ( isset($_REQUEST["_search"]) && strtolower($_REQUEST["_search"]) == 'true') ? true : false;
 
        $uni_id = isset($_REQUEST["uni_id"]) ? trim(strip_tags($_REQUEST["uni_id"])) : '';
        $uni_amount = isset($_REQUEST["uni_amount"]) ? trim(strip_tags($_REQUEST["uni_amount"])) : '';
        if ( !$uni_id || !ctype_digit($uni_id) || !$uni_amount )
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);
   
		$uni_amount = str_replace(',', '.', $uni_amount);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Сортировка
		switch( $sidx ) {
			case 'sto_id': $sidx = 'sto_id'; break;
			case 'sto_remain': $sidx = 'sto_remain'; break;
		}
		
// Фильтр
        $whc = array();
		$whc[] = "sto_uni_id=" . $db->quote($uni_id);

// Фильтр привилегий
		if( $rwd & PERM_BITS::READ_OTH ) $whc[] = '1 = 1';
		elseif( $rwd & PERM_BITS::READ_GRP ) 
			$whc[] = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::READ_OWN ) $whc[] = 'sto_user_id = '.$_SESSION['user_id'];
		else $whc[] = '1 = 0';

// Отсекаем списанные записи
		$whc[] = 'sto_retire_date IS NULL';
		
// Окончательно формируем условие
        $whereclaus = (count($whc) != 0 ) ? " WHERE " . implode(" AND ", $whc) : "";
		unset($whc);
            
// Получаем количество записей с учетом фильтра
        $sqlreq = "SELECT COUNT(*) AS count FROM stock AS sto ".$whereclaus;
        $recset = $db->query( $sqlreq );
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		$count = $row['count'];
		$recset->closeCursor();
            
// Пустая таблица
        if ($count == 0)
			throw new Exception(ERR_M::SUCCESS, 0);

// Получаем данные на unit
        $uni_joins = 
                " INNER JOIN metrics AS met ON met.met_id = units.uni_met_id ".
                " LEFT JOIN metrics AS opt ON opt.met_id = units.uni_met_opt_id ";

		$sql = 	"SELECT uni_name, uni_full, uni_met_id, met.met_name AS met_name, ".
					"IFNULL(uni_met_opt_id,'') AS uni_met_opt_id, ".
					"IFNULL(opt.met_name,'') AS met_opt_name, ".
					"IFNULL(uni_met_mul,'') AS uni_met_mul ".
				"FROM units ".$uni_joins." WHERE uni_id=".$db->quote($uni_id)." LIMIT 1";

		$rs = $db->query($sql);                  
		$row = $rs->fetch(PDO::FETCH_ASSOC);
		if( !$row )
			throw new Exception("Материал в справочнике не найден", 1);

		$uni_name = $row['uni_name'];
		$uni_full = $row['uni_full'];
		$uni_met_id = $row['uni_met_id'];
		$met_name = $row['met_name'];
		$uni_met_opt_id = $row['uni_met_opt_id'];
		$met_opt_name = $row['met_opt_name'];
		$uni_met_mul = $row['uni_met_mul'];
		$rs->closeCursor();
				
// Рассчитаем сколько всего страниц займут данные в БД
    	if( $count > 0 && $limit > 0) {
    		$total_pages = ceil($count/$limit);
    	} else {
    		$total_pages = 0;
    	}                  
 
		if ($page > $total_pages) $page=$total_pages;                  
 
// Формируем запрос
		$sqlreq = 	'SELECT  sto_id, sto_uni_id, sto_number, sto_remain, sto_metric, sto_price, sto_comment '.
					'FROM stock '.$whereclaus." ORDER BY ".$sidx." ".$sord.
		            " LIMIT ".$limit;

		$recset = $db->query($sqlreq);                  
 
// Формирование объекта для возврата
        
    	$data->page      = $page;
    	$data->total     = $total_pages;
    	$data->records   = $count;
    		
    // Строки данных для таблицы
		$i = 0;
		while($row = $recset->fetch(PDO::FETCH_ASSOC)) {
			
			$data->rows[$i]['id'] = $row['sto_id'];
/*
			$data->rows[$i]['cell'] = array(
					$row['sto_id'],
					$row['sto_uni_id'],
					$uni_name,
					$uni_full,
					$row['sto_number'],
					$row['sto_remain'],
				    $row['sto_metric'],
				    ($row['sto_metric'] == $uni_met_id) ? $met_name : 
						(($row['sto_metric'] == $uni_met_opt_id) ? $met_opt_name : ''),
				    $row['sto_price'],
				    $row['sto_comment']
		    );
*/
			$m_sto_number = ($row['sto_metric'] == $uni_met_id) ? $row['sto_number'] :
							(($row['sto_metric'] == $uni_met_opt_id) ? $row['sto_number'] * $uni_met_mul : '');							
			$m_sto_remain =	($row['sto_metric'] == $uni_met_id) ? $row['sto_remain'] :
							(($row['sto_metric'] == $uni_met_opt_id) ? $row['sto_remain'] * $uni_met_mul : '');							
			$m_sto_price =	($row['sto_metric'] == $uni_met_id) ? $row['sto_price'] :
							(($row['sto_metric'] == $uni_met_opt_id) ? $row['sto_price'] / $uni_met_mul : '');							

			$status = 0;
			if( $m_sto_remain < $uni_amount ) $status |= 0x1;
			$data->rows[$i]['cell'] = array(
					$row['sto_id'],
					$status,
					$uni_name,
					$uni_full,
					$m_sto_number,
					$m_sto_remain,
				    $met_name,
					$m_sto_price,							
				    $row['sto_comment']
		    );
		    $i++;
		}
    }
	catch (PDOException $e) {
		$data->userdata->errcode = 1;
		$data->userdata->errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$data->userdata->errcode = $e->getCode();
		$data->userdata->errmess = $e->getMessage();
	}
 
	return $data;
  }
  

/*  
  public function find() {
	$errcode = 0;
	$errmess = '';
    $data = array();
	
    try
    {
// Только зарегистрированные пользователи могут видеть данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

// Find - услуга общего пользования. Поэтому, маска должна быть READ_ANY
		$rwd = $_SESSION['priv']->units->rwd;
		if( ( $rwd & PERM_BITS::READ_ANY ) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);

// Проверяем данные
        $term   = isset($_REQUEST["term"]) ? trim(strip_tags($_REQUEST["term"])) : '';
        if ($term == '')
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);
   
// Открываем базу данных
		$db = App::me()->dbOpen();	

// Фильтр привилегий
		if( $rwd & PERM_BITS::READ_OTH ) $whs = '1 = 1';
		elseif( $rwd & PERM_BITS::READ_GRP ) 
			$whs = 'uni_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::READ_OWN ) $whs = 'uni_user_id = '.$_SESSION['user_id'];
		else $whs = '1 = 0';
		
// Формируем запрос
		$sqlreq =   "SELECT uni_id, uni_name, uni_full, uni_met_id, met_name FROM units AS uni ".
					"INNER JOIN metrics AS met ON met.met_id = uni.uni_met_id ".
					"WHERE ( uni_name LIKE ".$db->quote("%".$term."%").
					" OR uni_full LIKE ".$db->quote("%".$term."%").' ) AND '.$whs." ORDER BY uni_name";
		$recset = $db->query($sqlreq);                  
        while( $row = $recset->fetch(PDO::FETCH_ASSOC) ) {
            $item = new stdClass;
            $item->uni_id = $row['uni_id'];
			
			$num = mb_strlen($term,'UTF-8');
			$pos = mb_stripos( $row['uni_name'], $term, 0, 'UTF-8');
			if( !is_bool($pos) ) {
				$bterm = mb_substr($row['uni_name'], $pos, $num, 'UTF-8');
				$name = preg_replace( '/'.$bterm.'/u', '<b>'.$bterm.'</b>', $row['uni_name'] );				
			} else $name = $row['uni_name'];
			$pos = mb_stripos( $row['uni_full'], $term, 0, 'UTF-8');
			if( !is_bool($pos) ) {
				$bterm = mb_substr($row['uni_full'], $pos, $num, 'UTF-8');
				$full = preg_replace( '/'.$bterm.'/u', '<b>'.$bterm.'</b>', $row['uni_full'] );				
			} else $full = $row['uni_full'];
			
            $item->uni_name = $name;
			$item->uni_full = $full;
			$item->met_id = $row['uni_met_id'];
			$item->met_name = $row['met_name'];
            $data[] = $item;
        }
        $recset->closeCursor();
 
    }
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}
 
	return array('errcode'=>$errcode,'errmess'=>$errmess, 'data'=>$data);
  }
*/  
  
  public function insert() {

    $sto_inv_date	= isset($_POST['sto_inv_date']) ? trim(strip_tags($_POST['sto_inv_date'])) : '';
    $sto_inv_num	= isset($_POST['sto_inv_num']) ? trim(strip_tags($_POST['sto_inv_num'])) : '';
    $sto_inv_pos	= isset($_POST['sto_inv_pos']) ? trim(strip_tags($_POST['sto_inv_pos'])) : '';
    $sto_uni_id		= isset($_POST['sto_uni_id']) ? trim(strip_tags($_POST['sto_uni_id'])) : '';
    $uni_name		= isset($_POST['uni_name']) ? trim(strip_tags($_POST['uni_name'])) : '';
    $sto_number		= isset($_POST['sto_number']) ? trim(strip_tags($_POST['sto_number'])) : '';
    $sto_metric		= isset($_POST['sto_metric']) ? trim(strip_tags($_POST['sto_metric'])) : '';
    $sto_price		= isset($_POST['sto_price']) ? trim(strip_tags($_POST['sto_price'])) : '';
    $sto_comment	= isset($_POST['sto_comment']) ? trim(strip_tags($_POST['sto_comment'])) : '';
	
	$errcode = 0;
	$errmess = '';
    try
    {
// Открываем базу данных
		$db = App::me()->dbOpen();	

// Только зарегистрированные пользователи могут вносить данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);
		$sto_user_id = $_SESSION['user_id'];
		
//Есть ли разрешение на вставку записей
		$rwd = $_SESSION['priv']->stock->rwd;
		if( ($rwd & PERM_BITS::WRITE_OWN) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);

// Все ли данные переданы
		$errdata = "";
		
// sto_inv_date
	if( !$sto_inv_date ) $errdata .= ($errdata?'<br>':'')."- Не указана дата накладной.";
	elseif( ( $sto_inv_date = Tools::check_date($sto_inv_date) ) === false )
			$errdata .= ($errdata?'<br>':'')."- Дата накладной указана неправильно.";
	elseif( time() < strtotime( $sto_inv_date ) )
			$errdata .= ($errdata?'<br>':'')."- Дата накладной не может быть больше текущей даты";
			
// sto_inv_num
		if( $sto_inv_num == '' ) $errdata .= ($errdata?'<br>':'')."- Не указан номер накладной.";

// sto_inv_pos
		if( $sto_inv_pos == '' || !ctype_digit($sto_inv_pos) ) 
			$errdata .= ($errdata?'<br>':'')."- Не указан или указан неправильно номер позиции в накладной.";

// sto_uni_id & uni_name
		if( !$uni_name ) $errdata .= ($errdata?'<br>':'')."- Не указан шифр материала.";
		elseif( !$sto_uni_id || !ctype_digit( $sto_uni_id ) ) 
			$errdata .= ($errdata?'<br>':'').'- Не указан идентификатор материала.';
		else {
			$recset = $db->query('SELECT uni_name FROM units WHERE uni_id = '.$db->quote($sto_uni_id));                  
			$row = $recset->fetch(PDO::FETCH_ASSOC);
			if( $row['uni_name'] != $uni_name) {
				$errdata .= ($errdata?'<br>':'').'- Неправильно указан идентификатор материала.';
			}
			$recset->closeCursor();
		}

// sto_number
		if( !$sto_number )
			$errdata .= ($errdata?'<br>':'').'- Не указано количество материала.';
		else {
			$sto_number = str_replace(',', '.', $sto_number);
			if( !is_numeric( $sto_number ) )
				$errdata .= ($errdata?'<br>':'')."- Неправильно указано количество материала.";
		}

// sto_metric		
		if( !$sto_metric || !ctype_digit( $sto_metric ) ) 
			$errdata .= ($errdata?'<br>':'').'- Не указан идентификатор метрики.';
		
// sto_price
		if( !$sto_price )
			$errdata .= ($errdata?'<br>':'').'- Не указана цена материала.';
		else {
			$sto_price = str_replace(',', '.', $sto_price);
			if( !is_numeric( $sto_price ) )
				$errdata .= ($errdata?'<br>':'')."- Неправильно указана цена материала.";
		}

//				
// Если есть ошибки - можно уже закончить
//
		if( $errdata ) throw new Exception($errdata, 1);
		
// Может быть материал уже зачислен на склад
		$sto_key1 = preg_replace( '/[^0-9]/u', '', $sto_inv_date );
		$sto_key2 = preg_replace( '/[^а-яіїa-z0-9]/u', '', mb_strtolower( $sto_inv_num, 'UTF-8') );
		$sto_key  = substr( $sto_key1.' '.$sto_key2.' '.$sto_inv_pos, 0, 64);
		
		$sqlreq =	'SELECT COUNT(*) AS count FROM stock WHERE sto_key = '.$db->quote($sto_key);
		$recset = $db->query( $sqlreq );		
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		if( $row['count'] != 0 ) {
			throw new Exception('На склад уже зачислена эта позиция накладной.', 1);
        }    
		$recset->closeCursor();

// Пишем данные
        $sqlreq =   'INSERT INTO stock ( sto_inv_date, sto_inv_num, sto_inv_pos, '.
						'sto_uni_id, sto_number, sto_remain, '.
						'sto_metric, sto_price, sto_comment, '.
						'sto_create_date, sto_key, sto_user_id ) '.
                    'VALUES ( '.$db->quote($sto_inv_date).', '.$db->quote($sto_inv_num).', '.$db->quote($sto_inv_pos).', '.
								$db->quote($sto_uni_id).', '.$db->quote($sto_number).', '.$db->quote($sto_number).', '.
								$db->quote($sto_metric).', '.$db->quote($sto_price).', '.$db->quote($sto_comment).', '.
                                $db->quote(date('Y-m-d')).', '.$db->quote($sto_key).", ".$db->quote($sto_user_id). ")";
												
		$db->exec($sqlreq);
    }
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	return array('errcode'=>$errcode,'errmess'=>$errmess);
  }

  public function update() {

    $sto_id			= isset($_POST['id']) ? trim(strip_tags($_POST['id'])) : '';
    $sto_inv_date	= isset($_POST['sto_inv_date']) ? trim(strip_tags($_POST['sto_inv_date'])) : '';
    $sto_inv_num	= isset($_POST['sto_inv_num']) ? trim(strip_tags($_POST['sto_inv_num'])) : '';
    $sto_inv_pos	= isset($_POST['sto_inv_pos']) ? trim(strip_tags($_POST['sto_inv_pos'])) : '';
    $sto_uni_id		= isset($_POST['sto_uni_id']) ? trim(strip_tags($_POST['sto_uni_id'])) : '';
    $uni_name		= isset($_POST['uni_name']) ? trim(strip_tags($_POST['uni_name'])) : '';
    $sto_number		= isset($_POST['sto_number']) ? trim(strip_tags($_POST['sto_number'])) : '';
    $sto_metric		= isset($_POST['sto_metric']) ? trim(strip_tags($_POST['sto_metric'])) : '';
    $sto_price		= isset($_POST['sto_price']) ? trim(strip_tags($_POST['sto_price'])) : '';
    $sto_comment	= isset($_POST['sto_comment']) ? trim(strip_tags($_POST['sto_comment'])) : '';
	
	$errcode = 0;
	$errmess = '';
    try
    {
// Открываем базу данных
		$db = App::me()->dbOpen();	

// Только зарегистрированные пользователи могут вносить данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);
		$sto_user_id = $_SESSION['user_id'];
		
//Есть ли разрешение на вставку записей
		$rwd = $_SESSION['priv']->stock->rwd;
		if( ($rwd & PERM_BITS::WRITE_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);

// Все ли данные переданы
		$errdata = "";
		
// sto_id
		if( !$sto_id || !ctype_digit($sto_id) ) $errdata .= ($errdata?'<br>':'')."- Не указан идентификатор.";

// sto_inv_date
	if( !$sto_inv_date ) $errdata .= ($errdata?'<br>':'')."- Не указана дата накладной.";
	elseif( ( $sto_inv_date = Tools::check_date($sto_inv_date) ) === false )
			$errdata .= ($errdata?'<br>':'')."- Дата накладной указана неправильно.";
	elseif( time() < strtotime( $sto_inv_date ) )
			$errdata .= ($errdata?'<br>':'')."- Дата накладной не может быть больше текущей даты";
			
// sto_inv_num
		if( $sto_inv_num == '' ) $errdata .= ($errdata?'<br>':'')."- Не указан номер накладной.";

// sto_inv_pos
		if( $sto_inv_pos == '' || !ctype_digit($sto_inv_pos) ) 
			$errdata .= ($errdata?'<br>':'')."- Не указан или указан неправильно номер позиции в накладной.";

// sto_uni_id & uni_name
		if( !$uni_name ) $errdata .= ($errdata?'<br>':'')."- Не указан шифр материала.";
		elseif( !$sto_uni_id || !ctype_digit( $sto_uni_id ) ) 
			$errdata .= ($errdata?'<br>':'').'- Не указан идентификатор материала.';
		else {
			$recset = $db->query('SELECT uni_name FROM units WHERE uni_id = '.$db->quote($sto_uni_id));                  
			$row = $recset->fetch(PDO::FETCH_ASSOC);
			if( $row['uni_name'] != $uni_name) {
				$errdata .= ($errdata?'<br>':'').'- Неправильно указан идентификатор материала.';
			}
			$recset->closeCursor();
		}

// sto_number
		if( !$sto_number )
			$errdata .= ($errdata?'<br>':'').'- Не указано количество материала.';
		else {
			$sto_number = str_replace(',', '.', $sto_number);
			if( !is_numeric( $sto_number ) )
				$errdata .= ($errdata?'<br>':'')."- Неправильно указано количество материала.";
		}

// sto_metric		
		if( !$sto_metric || !ctype_digit( $sto_metric ) ) 
			$errdata .= ($errdata?'<br>':'').'- Не указан идентификатор метрики.';
		
// sto_price
		if( !$sto_price )
			$errdata .= ($errdata?'<br>':'').'- Не указана цена материала.';
		else {
			$sto_price = str_replace(',', '.', $sto_price);
			if( !is_numeric( $sto_price ) )
				$errdata .= ($errdata?'<br>':'')."- Неправильно указана цена материала.";
		}

//				
// Если есть ошибки - можно уже закончить
//
		if( $errdata ) throw new Exception($errdata, 1);
		
// Есть ли разрешение на апдейт этой записи
// Заодно считываем дату создания записи
		if( $rwd & PERM_BITS::WRITE_OTH ) $where = '1 = 1';
		elseif( $rwd & PERM_BITS::WRITE_GRP ) 
			$where = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::WRITE_OWN ) $where = 'sto_user_id = '.$_SESSION['user_id'];
		else $where = '1 = 0';
		$where .= ' AND sto_id = '.$db->quote($sto_id);
		
		$sqlreq = 'SELECT sto_create_date, sto_number, sto_remain FROM stock WHERE '.$where.' LIMIT 1';
		$recset = $db->query( $sqlreq );		
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		if( !$row ) {
			throw new Exception(ERR_M::DATA_OWNER_DISABLED, 99);
        }
		
		$o_sto_create_date = $row['sto_create_date'];
		$o_sto_number = $row['sto_number'];
		$o_sto_remain = $row['sto_remain'];
		$recset->closeCursor();

// Закончилось время для корректировки или начата выдача со склада
		if( date('Y-m-d') != $o_sto_create_date || $o_sto_number != $o_sto_remain )
			throw new Exception(ERR_M::DATA_UPDATE_DISABLED, 99);
		
// Может быть материал уже зачислен на склад
		$sto_key1 = preg_replace( '/[^0-9]/u', '', $sto_inv_date );
		$sto_key2 = preg_replace( '/[^а-яіїa-z0-9]/u', '', mb_strtolower( $sto_inv_num, 'UTF-8') );
		$sto_key  = substr( $sto_key1.' '.$sto_key2.' '.$sto_inv_pos, 0, 64);
		
		$sqlreq =	'SELECT COUNT(*) AS count FROM stock WHERE sto_key = '.$db->quote($sto_key).
					' AND sto_id != '.$db->quote($sto_id);
		$recset = $db->query( $sqlreq );		
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		if( $row['count'] != 0 ) {
			throw new Exception('На складе уже есть эта позиция накладной.', 1);
        }    
		$recset->closeCursor();

// Пишем данные
        $sqlreq =   'UPDATE stock SET '.
						'sto_inv_date = '.$db->quote($sto_inv_date).', '.
						'sto_inv_num = '.$db->quote($sto_inv_num).', '.
						'sto_inv_pos = '.$db->quote($sto_inv_pos).', '.
						'sto_uni_id = '.$db->quote($sto_uni_id).', '.
						'sto_number = '.$db->quote($sto_number).', '.
						'sto_metric = '.$db->quote($sto_metric).', '.
						'sto_price = '.$db->quote($sto_price).', '.
						'sto_comment = '.$db->quote($sto_comment).', '.
						'sto_key = '.$db->quote($sto_key)." ".
					'WHERE sto_id = '.$db->quote($sto_id);
												
		$db->exec($sqlreq);
    }
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	return array('errcode'=>$errcode,'errmess'=>$errmess);
  }


  public function delete() {
    $errmess = "";
	$errcode = 0;
		
    $sto_ids = (isset($_REQUEST['id']) && $_REQUEST['id'] != '') ?
        explode(",", $_REQUEST["id"], 100) : array();

    try
    {
// Только зарегистрированные пользователи могут удалять данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

// Есть ли разрешение на удаление хоть какой либо записи
		$rwd = $_SESSION['priv']->stock->rwd;
		if( ($rwd & PERM_BITS::DELETE_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);
		
        if (!Tools::is_numeric_array( $sto_ids ))
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);
        
		$sto_id_list = implode(',', $sto_ids);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Есть ли разрешение на удаление этих записей
		if( $rwd & PERM_BITS::DELETE_OTH ) $where = '1 = 1';
		elseif( $rwd & PERM_BITS::DELETE_GRP ) 
			$where = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::DELETE_OWN ) $where = 'sto_user_id = '.$_SESSION['user_id'];
		else $where = '1 = 0';
		$where .= ' AND sto_id IN ('.$sto_id_list.')';
		
		$sqlreq = 'SELECT sto_id, sto_create_date, sto_number, sto_remain FROM stock WHERE '.$where;
		$recset = $db->query( $sqlreq );
		$ids = array();
		$errdata = '';
		$currdate = date('Y-m-d');
		while($row = $recset->fetch(PDO::FETCH_ASSOC) ) {
			$ids[] = $row['sto_id'];
			if( $currdate != $row['sto_create_date'])
				$errdata .= ($errdata?'<br>':'').'- ID:'.$row['sto_id'].' Время на внесение изменений закончилось.';
			if( $row['sto_number'] != $row['sto_remain'])
				$errdata .= ($errdata?'<br>':'').'- ID:'.$row['sto_id'].' По этой позиции началась выдача.';
		}
		$recset->closeCursor();
		if( count($ids) != count($sto_ids) ) {
			foreach( $sto_ids as $sto_id) {
				if( is_bool( array_search($sto_id, $ids) ) )
					$errdata .= ($errdata?'<br>':'').'- ID:'.$sto_id.' У Вас нет прав на изменение этой позиции.';
			}
        }    
		
		if( $errdata) throw new Exception($errdata, 1);
		
// Удаляем записи из справочника
        $sqlreq = "DELETE FROM stock WHERE sto_id IN (".$sto_id_list.")";
        $db->exec($sqlreq);
	}
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	return array('errcode'=>$errcode,'errmess'=>$errmess);
  }
  
  
  public function retire() {
    $errmess = "";
	$errcode = 0;
		
    $sto_ids = (isset($_REQUEST['sto_ids']) && $_REQUEST['sto_ids'] != '') ?
        explode(",", $_REQUEST["sto_ids"], 100) : array();

    try
    {
// Только зарегистрированные пользователи могут удалять данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

// Есть ли разрешение на удаление хоть какой либо записи
		$rwd = $_SESSION['priv']->stock->rwd;
		if( ($rwd & PERM_BITS::WRITE_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);
		
        if (!Tools::is_numeric_array( $sto_ids ))
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);
        
		$sto_id_list = implode(',', $sto_ids);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Есть ли разрешение на изменение этих записей
		if( $rwd & PERM_BITS::WRITE_OTH ) $where = '1 = 1';
		elseif( $rwd & PERM_BITS::WRITE_GRP ) 
			$where = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::WRITE_OWN ) $where = 'sto_user_id = '.$_SESSION['user_id'];
		else $where = '1 = 0';
		$where .= ' AND sto_id IN ('.$sto_id_list.')';
		
		$sql = 'SELECT sto_id FROM stock WHERE '.$where;
		$rs = $db->query( $sql );
		$ids = array();
		$errdata = '';
		while($sto = $rs->fetchObject() ) {
			$ids[] = $sto->sto_id;
		}
		$rs->closeCursor();
		if( count($ids) != count($sto_ids) ) {
			foreach( $sto_ids as $sto_id) {
				if( is_bool( array_search($sto_id, $ids) ) )
					$errdata .= ($errdata?'<br>':'').'- ID:'.$sto_id.' У Вас нет прав на изменение этой позиции.';
			}
        }    
		
		if( $errdata) throw new Exception($errdata, 1);
		
// Проводим списание
        $sql = "UPDATE stock SET sto_retire_date = '".date('Y-m-d')."' WHERE sto_id IN (".$sto_id_list.")";
        $db->exec($sql);
	}
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	return array('errcode'=>$errcode,'errmess'=>$errmess);
  }


  public function unretire() {
    $errmess = "";
	$errcode = 0;
		
    $sto_ids = (isset($_REQUEST['sto_ids']) && $_REQUEST['sto_ids'] != '') ?
        explode(",", $_REQUEST["sto_ids"], 100) : array();

    try
    {
// Только зарегистрированные пользователи могут изменять данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

// Есть ли разрешение на изменение хоть какой либо записи
		$rwd = $_SESSION['priv']->stock->rwd;
		if( ($rwd & PERM_BITS::WRITE_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);
		
        if (!Tools::is_numeric_array( $sto_ids ))
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);
        
		$sto_id_list = implode(',', $sto_ids);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Есть ли разрешение на изменение этих записей
		if( $rwd & PERM_BITS::WRITE_OTH ) $where = '1 = 1';
		elseif( $rwd & PERM_BITS::WRITE_GRP ) 
			$where = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::WRITE_OWN ) $where = 'sto_user_id = '.$_SESSION['user_id'];
		else $where = '1 = 0';
		$where .= ' AND sto_id IN ('.$sto_id_list.')';
		
		$sql = 'SELECT sto_id FROM stock WHERE '.$where;
		$rs = $db->query( $sql );
		$ids = array();
		$errdata = '';
		while($sto = $rs->fetchObject() ) {
			$ids[] = $sto->sto_id;
		}
		$rs->closeCursor();
		if( count($ids) != count($sto_ids) ) {
			foreach( $sto_ids as $sto_id) {
				if( is_bool( array_search($sto_id, $ids) ) )
					$errdata .= ($errdata?'<br>':'').'- ID:'.$sto_id.' У Вас нет прав на изменение этой позиции.';
			}
        }    
		
		if( $errdata) throw new Exception($errdata, 1);
		
// Проводим унсписание
        $sql = "UPDATE stock SET sto_retire_date = NULL WHERE sto_id IN (".$sto_id_list.")";
        $db->exec($sql);
	}
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	return array('errcode'=>$errcode,'errmess'=>$errmess);
  }


  public function crossindex() {
  
    $data = new jqGridData();
    try
    {
// Только зарегистрированные пользователи могут видеть данные
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

		$rwd = $_SESSION['priv']->stock->rwd;
		if( !$rwd  ) throw new Exception(ERR_M::DATA_ACC_DISABLED, 99);

// Проверяем данные
        $page    = ( isset($_REQUEST["page"]) && $_REQUEST["page"] > 0 ) ? $_REQUEST["page"] : 1;
        $limit    = ( isset($_REQUEST["rows"]) && $_REQUEST["rows"] > 0 ) ? $_REQUEST["rows"] : 1;
        $sidx    = ( isset($_REQUEST["sidx"]) && $_REQUEST["sidx"] != '' ) ? $_REQUEST["sidx"] : 'sto_id';
        $sord    = ( isset($_REQUEST["sord"]) && strtolower($_REQUEST["sord"]) == 'desc' ) ? 'DESC' : 'ASC';
        $search    = ( isset($_REQUEST["_search"]) && strtolower($_REQUEST["_search"]) == 'true') ? true : false;
 
        $leaf_id = isset($_REQUEST["leaf_id"]) ? $_REQUEST["leaf_id"] : '';             
        if ( !ctype_digit($leaf_id) )
			throw new Exception(ERR_M::PROTOCOL_ERROR, 1);

// Открываем базу данных
		$db = App::me()->dbOpen();	

// Сортировка
		switch( $sidx ) {
			case 'sto_id': $sidx = 'sto.sto_id'; break;
			case 'sto_inv_date': $sidx = 'sto.sto_key'; break;
			case 'sto_inv_num': $sidx = 'sto.sto_inv_num'; break;
			case 'sto_remain': $sidx = 'sto.sto_remain'; break;
			case 'uni_name': $sidx = 'uni.uni_name'; break;
			case 'sto_retire_date': $sidx = 'sto.sto_retire_date'; break;
		}
		
// Фильтр
        $whc = array();
        if( $search )
        {
            if(isset($_REQUEST["sto_id"]) && is_numeric($_REQUEST["sto_id"]) ) {
				$whc[] = "sto_id=" . $db->quote($_REQUEST["sto_id"]);
		    }
            
            if(isset($_REQUEST["sto_inv_date"]) && ( $dt = Tools::date_to_search_str( $_REQUEST["sto_inv_date"] )) != "") {
				$whc[] = "sto_inv_date LIKE " . $db->quote("%".$dt."%");
            }
			
            if(isset($_REQUEST["sto_inv_num"]) && $_REQUEST["sto_inv_num"] != "") {
				$whc[] = "sto_inv_num LIKE " . $db->quote("%".$_REQUEST["sto_inv_num"]."%");
            }
			
            if(isset($_REQUEST["uni_name"]) && $_REQUEST["uni_name"] != "") {
		    	$whc[] = "uni.uni_name LIKE " . $db->quote("%".$_REQUEST["uni_name"]."%");
            }
			
            if(isset($_REQUEST["uni_full"]) && $_REQUEST["uni_full"] != "") {
		    	$whc[] = "uni.uni_full LIKE " . $db->quote("%".$_REQUEST["uni_full"]."%");
            }
			
            if(isset($_REQUEST["sto_retire_date"]) && ( $dt = Tools::date_to_search_str( $_REQUEST["sto_retire_date"] )) != "") {
				$whc[] = "sto_retire_date LIKE " . $db->quote("%".$dt."%");
            }
			
		}

// Фильтр привилегий
		if( $rwd & PERM_BITS::READ_OTH ) $whc[] = '1 = 1';
		elseif( $rwd & PERM_BITS::READ_GRP ) 
			$whc[] = 'sto_user_id IN (SELECT user_id FROM users WHERE cat_id = '.$_SESSION['cat_id'].')';
		elseif( $rwd & PERM_BITS::READ_OWN ) $whc[] = 'sto_user_id = '.$_SESSION['user_id'];
		else $whc[] = '1 = 0';

// Отсекаем списанные записи
		$whc[] = 'sto_retire_date IS NOT NULL';
		
// Окончательно формируем условие
        $whereclaus = (count($whc) != 0 ) ? " WHERE " . implode(" AND ", $whc) : "";
		unset($whc);
            
// Получаем количество записей с учетом фильтра
		$uni_filter = $leaf_id ? "AND uni_leaf_id = ".$db->quote( $leaf_id )." " : '';
			
        $join1 = " INNER JOIN units AS uni ON uni.uni_id = sto.sto_uni_id ".$uni_filter;
        $join2 = " INNER JOIN metrics AS met ON met.met_id = sto.sto_metric ";
            
        $sqlreq = "SELECT COUNT(*) AS count FROM stock AS sto ".$join1.$whereclaus;
        $recset = $db->query( $sqlreq );
		$row = $recset->fetch(PDO::FETCH_ASSOC);
		$count = $row['count'];
		$recset->closeCursor();
            
// Пустая таблица
        if ($count == 0)
			throw new Exception(ERR_M::SUCCESS, 0);
            
// Рассчитаем сколько всего страниц займут данные в БД
    	if( $count > 0 && $limit > 0) {
    		$total_pages = ceil($count/$limit);
    	} else {
    		$total_pages = 0;
    	}                  
 
		if ($page > $total_pages) $page=$total_pages;                  
 
		$start = $limit*$page - $limit;                   
		if($start < 0) $start = 0;                  
 
// Формируем запрос
		$sqlreq = 	'SELECT  sto_id, sto_inv_date, sto_inv_num, sto_inv_pos, sto_uni_id, uni_name, uni_full, '.
							'sto_number, sto_remain, sto_metric, met_name, sto_price, sto_retire_date, sto_comment, sto_create_date '.
					'FROM stock AS sto '.$join1.$join2.$whereclaus." ORDER BY ".$sidx." ".$sord.
		            " LIMIT ".$start.", ".$limit;

		$recset = $db->query($sqlreq);                  
 
// Формирование объекта для возврата
        
    	$data->page      = $page;
    	$data->total     = $total_pages;
    	$data->records   = $count;
    		
    // Строки данных для таблицы
		$currdate = date('Y-m-d');
		$i = 0;
		while($row = $recset->fetch(PDO::FETCH_ASSOC)) {
			$status = 0;
			if( $currdate != $row['sto_create_date'] ) $status |= 2;
			if( $row['sto_number'] != $row['sto_remain'] ) $status |= 4;
			
			$data->rows[$i]['id'] = $row['sto_id'];
			$data->rows[$i]['cell'] = array(
					$status,
					$row['sto_id'],
					Tools::str_iso2local_date( $row['sto_inv_date'] ),
					$row['sto_inv_num'],
					$row['sto_inv_pos'],
					$row['sto_uni_id'],
					$row['uni_name'],
					$row['uni_full'],
					$row['sto_number'],
					$row['sto_remain'],
				    $row['sto_metric'],
				    $row['met_name'],
				    $row['sto_price'],
					Tools::str_iso2local_date( $row['sto_retire_date'] ),
				    $row['sto_comment']
		    );
		    $i++;
		}
    }
	catch (PDOException $e) {
		$data->userdata->errcode = 1;
		$data->userdata->errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$data->userdata->errcode = $e->getCode();
		$data->userdata->errmess = $e->getMessage();
	}
 
	return $data;
  }
  
  
} // End of Stock class
?>